package org.xtext.runtime.plan;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.xtext.runtime.formula.IFormula;
import org.xtext.runtime.formula.Predicate;
import org.xtext.runtime.interpreter.Agent;
import org.xtext.runtime.term.Variable;
import org.xtext.runtime.util.Bindings;
import org.xtext.runtime.util.EvaluateTermsVisitor;

public class UpdateStep implements IPlanStep {
	protected IFormula step;
	protected String op;
//	private Predicate selfSource = new Predicate("source", new ITerm[] { new StringTerm("self") });
	
	public UpdateStep(String op, IFormula step) {
		this.op = op;
		this.step = step;
	}
	
	public IFormula formula() {
		return step;
	}

	public String toString() {
		return toString("");
	}
	
	public String toString(String tabs) {
		return tabs + op + step;
	}

	public String toFullString(String tabs) {
		return toString(tabs);
	}
	
	@Override
	public void handle(Agent agent, PlanStack planStack) {
		EvaluateTermsVisitor visitor = new EvaluateTermsVisitor(agent);
		IFormula formula = (IFormula) step.accept(visitor);
		
		if (op.equals("+")) {
			adopt(agent, formula);
		} else if (op.equals("-")) {
			drop(agent, formula);
		}
	}
	
	protected void adopt(Agent agent, IFormula formula) {
		if (Predicate.class.isInstance(formula)) {
			agent.addBelief((Predicate) formula.copy());
		}
	}
	
	protected void drop(Agent agent, IFormula formula) {
		if (Predicate.class.isInstance(formula)) {
			agent.removeBelief((Predicate) formula.copy());
		}
	}

	@Override
	public Set<Variable> variables() {
		Set<Variable> variables = new HashSet<Variable>();
		variables.addAll(this.step.variables());
		return variables;
	}

	@Override
	public UpdateStep copy(Map<String, Variable> vars) {
		UpdateStep stp = new UpdateStep(op, step.copy(vars));
		return stp;
	}

	@Override
	public UpdateStep apply(Bindings bindings) {
//		return new UpdateStep(op, step.apply(bindings));
		step = step.apply(bindings);
		return this;
	}

	@Override
	public void reset() {
	}
}
